package com.yellowcong.test;


import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;


public class ZookeeperUtils {

	//基于ip查询
	//private static final String CONNECT_PATH = "47.90.92.56:15513";

	// 连接到ZK服务，多个可以用逗号分割写
	//zk = new ZooKeeper("192.168.19.130:2181,192.168.19.130:2182,192.168.19.130:2183", Test.SESSION_TIMEOUT, this.wh);

	private static final String CONNECT_PATH = "127.0.0.1:2181";


	//基于连接地址来查询数据
	//ip.chinaz.com 地址来查询ip
	private static final String CONNECT_PATH_URL = "server.ngrok.cc:15513";

	//设置超时 20s,我使用的是sunny的内网穿透
	private static final int SESSION_TIME_OUT = 20000;

	//设定编码
	private static final Charset charset = Charset.forName("UTF-8");

	//连接服务端
	private static ZooKeeper  zk= null;

	//用于存储nodes节点，然后删除
	//private static List<String> nodes = null;

	static{
		try {
			//连接服务端
			 zk = new ZooKeeper(CONNECT_PATH,SESSION_TIME_OUT, new Watcher(){

				// 监控所有被触发的事
				@Override
				public void process(WatchedEvent event) {
					System.out.println("已经触发了" + event.getType() + "事件！");
				}
			});
		} catch (IOException e) {
			// TODO 自動生成された catch ブロック
			e.printStackTrace();
		}
	}



	public static void main(String [] args) throws Exception{



		System.out.println(ZookeeperUtils.exists("/java")?"存在节点":"不存在节点");

		/*for(int i=0;i<100;i++){
			String rndStr = UUID.randomUUID().toString().substring(0,8);
			String nodesName = "/"+rndStr;
			//创建节点
			zk.create(nodesName, rndStr.getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
		}
		ZookeeperUtils.delete("/");
*/
		Set<String> nodes = ZookeeperUtils.getNodes("/");
		nodes = reserveNode(nodes);
		for(String node:nodes){
			System.out.println(node+"--------->"+getData(node));
		}

		/*if(stat != null){
			//zk不支持递归删除节点,所以必须先将子节点删除才能删除父节点
			//删除节点
			//zk.delete("/java", -1);
			//ZookeeperUtils.deleteNode("/java");
			ZookeeperUtils.getNodes("/test2/tsetde");
			for(String node:nodes){
				System.out.println(node);
			}


		}

		//获取数据
		byte [] data = zk.getData(nodesName, true, null);
		System.out.println(new String(data,charset));

		//创建子节点后，上面在子节点写的数据就被覆盖了
		//zk.create("/java/demo", "demo".getBytes(charset), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

		//获取数据
		byte [] data2 = zk.getData("/java", true, null);
		System.out.println(new String(data2,charset));

		//更新节点
		//zk.setData("/java", "nb".getBytes(charset), -1);

		// 取出子目录节点列表
		System.out.println(zk.getChildren("/",true));


		//关闭连接
		zk.close();*/

	}
	/**
	 * 删除节点，级联删除操作
	 * @param node
	 */
	public static void delete(String node) throws Exception{
		//获取节点数据
		Set<String> nodes = ZookeeperUtils.getNodes(node);
		nodes = reserveNode(nodes);
		for(String child:nodes){
			if(child.indexOf("/zookeeper") < 0){
				zk.delete(child, -1);
			}
		}

		//清空node的数据
	}
	/**
	 * 获取节点数据
	 * @throws Exception
	 * @throws KeeperException
	 */
	public static String getData(String node) throws Exception{
		byte [] result = zk.getData(node, true, null);
		return new String(result,charset);
	}
	/**
	 * 获取节点数据
	 * @param path
	 * @return
	 * @throws Exception
	 */
	public static Set<String> getNodes(String path) throws Exception{

		//判断是否存在节点
		Stat stat = zk.exists(path,null); //获取节点信息
		if(stat == null){
			return null;
		}
		Set<String> nodes = new LinkedHashSet<String>();
		iterator(path,nodes);

		return nodes;
	}

	/**
	 * 迭代文件夹，判断数据情况
	 * @param path
	 * @param nodes
	 * @throws Exception
	 */
	private static void iterator(String path,Set<String> nodes) throws Exception{
		//当时子节点的情况，直接添加，不继续遍历了
		if(!ZookeeperUtils.isParentNode(path)){
			nodes.add(path);
		}else{
			List<String> childs = zk.getChildren(path, false);
			for(String node:childs){
				String childPath = path+"/"+node;
				//当时直接遍历父节点的情况
				if(path.equals("/")){
					childPath = path+node;
				}
				nodes.add(childPath);
				iterator(childPath,nodes);
			}
		}
	}

	/**
	 * 将节点的顺序重新排序，从后往前排序，最后遍历出来的，最先显示
	 * @param path
	 * @return
	 * @throws Exception
	 */
	public static Set<String> reserveNode(Set<String> nodes) throws Exception{
		//由于Set不能直接通过index来取出数据来，所以将他转为数组，然后获取数据
		Object [] nodesArr = nodes.toArray();
		int i=nodes.size()-1;
		Set<String> set = new LinkedHashSet<String>();
		for(;i>=0;i--){
			set.add(nodesArr[i].toString());
		}
		return set;
	}

	/**
	 * 判断是否是父类节点
	 * @param node
	 * @return
	 * @throws Exception
	 */
	public static boolean isParentNode(String node) throws Exception{
		List<String> childs = zk.getChildren(node, false);
		return childs.size()>0;
	}


	/**
	 * 判断节点是否存在
	 * @param node 节点名称
	 * @return
	 * @throws Exception
	 */
	public static boolean exists(String node) throws Exception{
		Stat stat = zk.exists(node,null); //获取节点信息
		return (stat != null);
	}
}
